Pourquoi tester son code ? Les tests permettent de vérifier que votre code fonctionne comme prévu, d'éviter les régressions et de faciliter la maintenance. Un code testé est un code fiable.
1. L'instruction assert
assert est une assertion qui vérifie qu'une condition est vraie. Si elle est fausse, une exception AssertionError est levée.
assert condition, "message d'erreur optionnel"
x = 10
assert x > 0, "x doit être positif"
assert x == 5, "x devrait être 5"
def diviser(a, b):
assert b != 0, "Division par zéro impossible"
return a / b
Attention : Les assertions peuvent être désactivées avec l'option -O de Python. Ne les utilisez pas pour la validation de données critiques en production.
2. Tests Unitaires avec unittest
Le module unittest est intégré à Python et permet d'écrire des tests structurés.
def additionner(a, b):
return a + b
def est_pair(n):
return n % 2 == 0
import unittest
class TestCalculs(unittest.TestCase):
def test_additionner(self):
self.assertEqual(additionner(2, 3), 5)
self.assertEqual(additionner(-1, 1), 0)
self.assertEqual(additionner(0, 0), 0)
def test_est_pair(self):
self.assertTrue(est_pair(4))
self.assertFalse(est_pair(5))
self.assertTrue(est_pair(0))
def test_additionner_negatifs(self):
self.assertLess(additionner(-5, -3), 0)
if __name__ == '__main__':
unittest.main()
3. Tests avec pytest
pytest est une alternative plus simple et plus puissante à unittest. (Nécessite pip install pytest)
def additionner(a, b):
return a + b
def diviser(a, b):
return a / b
def test_additionner():
assert additionner(2, 3) == 5
assert additionner(-1, 1) == 0
assert additionner(0, 0) == 0
def test_diviser_par_zero():
import pytest
with pytest.raises(ZeroDivisionError):
diviser(10, 0)
import pytest
@pytest.mark.parametrize("a,b,attendu", [
(1, 1, 2),
(2, 3, 5),
(-1, 5, 4),
])
def test_additionner_param(a, b, attendu):
assert additionner(a, b) == attendu
Exécution des tests :
python -m unittest discover pour unittest
pytest ou pytest -v pour pytest (plus lisible)
4. Débogage avec pdb
pdb est le débogueur interactif intégré de Python.
Commandes pdb essentielles :
l (list) - Affiche le code autour de la ligne actuelle
n (next) - Exécute la ligne suivante
s (step) - Entre dans une fonction
c (continue) - Continue l'exécution
p variable (print) - Affiche la valeur d'une variable
q (quit) - Quitte le débogueur
b 10 (break) - Place un point d'arrêt à la ligne 10
import pdb
def fonction_problematique(x, y):
resultat = x + y
pdb.set_trace()
return resultat * 2
def autre_fonction(valeur):
breakpoint()
return valeur ** 2
def calculer_moyenne(notes):
total = 0
for note in notes:
total += note
breakpoint()
return total / len(notes)
notes = [15, 12, 18, 14]
moyenne = calculer_moyenne(notes)
print(moyenne)
5. Journalisation (logging)
Le module logging est plus professionnel que print() pour le suivi et le débogage.
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("app.log"),
logging.StreamHandler()
]
)
logging.debug("Message de débogage - détails techniques")
logging.info("Message d'information - fonctionnement normal")
logging.warning("Message d'avertissement - problème potentiel")
logging.error("Message d'erreur - problème mais programme continue")
logging.critical("Message critique - programme va s'arrêter")
import logging
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
class GestionnaireUtilisateur:
def __init__(self):
self.utilisateurs = {}
logging.info("GestionnaireUtilisateur initialisé")
def ajouter(self, nom, age):
if nom in self.utilisateurs:
logging.warning(f"Tentative d'ajout d'un utilisateur existant: {nom}")
return False
self.utilisateurs[nom] = age
logging.debug(f"Utilisateur ajouté: {nom}, {age} ans")
return True
def obtenir(self, nom):
try:
return self.utilisateurs[nom]
except KeyError:
logging.error(f"Utilisateur non trouvé: {nom}")
return None
6. Bonnes pratiques de débogage
Conseils essentiels :
- ✔️ Lisez attentivement les messages d'erreur et les tracebacks
- ✔️ Isolez le problème (réduisez le code au minimum reproduisant le bug)
- ✔️ Utilisez
print() stratégiquement, mais préférez logging pour les projets sérieux
- ✔️ Testez vos hypothèses une par une
- ✔️ Écrivez des tests avant de corriger un bug (TDD - Test Driven Development)
- ✔️ Utilisez un IDE avec débogueur intégré (VSCode, PyCharm)
if __debug__:
print("Ce message n'apparaît qu'en mode debug")
logging.debug("Mode debug actif")
Attention : Ne laissez jamais de pdb.set_trace() ou de breakpoint() en production. Utilisez des variables d'environnement ou des flags pour activer conditionnellement le débogage.